﻿// Handles DOM events
// Events are added to the DOM once the element is rendered.
define([
    'Wjs/Wjs'
],
function () {
    'use strict';

    return Wjs.defineOnce({

        type: 'DomEvents',

        internal: {

            construct: function () {

                // This array of events is needed to track the added events when we need to remove them
                this._events = [];  // There can be multiple events with the same name attached to the element so we use an array
                
                // The array of handler names to copy them when cloning
                this._handlerNames = [];
            },

            // Event handlers

            listeners: {

                onDomElementCreated: function () {

                    // Attach the stored events
                    if (this._events) {

                        this._events.forEach(function (evt, i) {

                            this.domEl.addEventListener(evt.name, evt.handler, false);
                        },
                        this);
                    }
                },

                onDestroy: function () {

                    if (this._events) {

                        this.clearEvents();  // Clear the events of this element
                    }
                },

                onCloned: function (cloned) {

                    this.copyDomEventsTo(cloned);
                }

            }

        },

        // Sets a handler for the DOM event and attaches an event if not attached already
        onDomEvent: function (name, fcn, assign) {
            var handlerName = name + 'Handler';

            if (assign) {

                this[handlerName] = fcn;
            }
            else { // Chain

                this[handlerName] = Wjs.chain(this[handlerName], fcn);
            }

            if (this._handlerNames.indexOf(handlerName) < 0) { // Not added

                this._handlerNames.push(handlerName);
            }

            // If there is a handler but there is no event attached, attach the event
            if (this[handlerName] && !this._events[name]) {

                this.addEvent(name, this[handlerName]);
            }

            return this;
        },

        addEvent: function (name, fcn) {
            var me = this,
                handler = function (evt) {

                    return fcn.call(me, evt); // Wrap the callback so we pass the element as this
                };

            me._events.push({
                name: name,
                handler: handler,
                original: fcn // The original function in case we are going to copy the events
            });

            if (me.isRendered()) { // If rendered attach it also to the DOM element

                me.domEl.addEventListener(name, handler, false);
            }

            return this;
        },

        // Add events to this element
        addEvents: function (events) {

            for (name in events) {

                this.addEvent(name, events[name]);
            }

            return this;
        },

        // Removes the events that have the same name from the element
        removeEvent: function (name, handler) {

            this._events.forEach(function (evt, i) {

                if (evt.name == name && evt.original == handler || evt.original) { // If the handler is not provided then remove all the events by name

                    if (this.isRendered()) { // If rendered dettach it also from the DOM element

                        this.domEl.removeEventListener(evt.name, evt.handle, false);
                    }

                    this._events.splice(i, 1); // Remove it form the array of events
                }
            },
            this);
        },

        // Removes all the events from the element
        clearEvents: function () {

            if (this.isRendered()) { // If rendered dettach it also from the DOM element

                this._events.forEach(function (evt, i) {

                    this.domEl.removeEventListener(evt.name, evt.handler, false);
                },
                this);
            }

            this._events.length = 0; // Clear the array
        },

        copyDomEventsTo: function (view) {

            // Copy the handlers
            this._handlerNames.forEach(function (handlerName) {

                view[handlerName] = this[handlerName];
            },
            this);

            // Attach the events
            this._events.forEach(function (event) {

                view.addEvent(event.name, event.original);
            });
        }

    });

});